package io.github.zeleven.mua;

import io.github.zeleven.mua.bean.StringCache;
import io.github.zeleven.mua.utl.PreferenceUtil;
import io.github.zeleven.mua.utl.ScreenUtils;
import io.github.zeleven.mua.view.BaseTextField;
import ohos.agp.components.*;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.CommonDialog;
import ohos.agp.window.dialog.ToastDialog;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.util.List;

/**
 * EditorAction
 *
 * @since 2021-05-11
 */
public class EditorAction {
    private static final int INT = 0x001234;
    private static final int INT_2 = 2;
    private static final int INT_6 = 6;
    private static final int INT_7 = 7;
    private static final int INT_1 = 1;
    private HiLogLabel hiLogLabel = new HiLogLabel(HiLog.LOG_APP, INT, "zf------");
    private Context context; // context instance
    private BaseTextField editText; // edittext instance

    /**
     * EditorAction
     */
    public EditorAction() {
    }

    /**
     * EditorAction
     *
     * @param context
     */
    public EditorAction(Context context) {
        this.context = context;
    }

    /**
     * EditorAction
     *
     * @param context
     * @param editText
     */
    public EditorAction(Context context, BaseTextField editText) {
        this.context = context;
        this.editText = editText;
    }

    /**
     * Insert markdown heading markup, if there was nothing input, insert "#" markup to 0 position.
     * Otherwise, insert the markup at position which after line break.
     */
    public void heading() {
        int start = editText.getStartPosition();
        StringBuilder stringBuilder = new StringBuilder();
        String textContent = editText.getText();
        int lineBreakPos = textContent.lastIndexOf("\n", start);
        int insertPos;
        if (lineBreakPos == -INT_1) {
            insertPos = 0;
        } else {
            insertPos = lineBreakPos + 1;
        }
        stringBuilder.append(editText.getText());
        stringBuilder.insert(insertPos, "#");
        String afterInsert = "";
        if (insertPos != 0) {
            if (insertPos < editText.getText().length()) {
                afterInsert = editText.getText().substring(insertPos + 1);
            }
        }
        if (!afterInsert.startsWith("#") && !afterInsert.startsWith(" ")) {
            stringBuilder.insert(insertPos + 1, " ");
        }
        editText.setText(stringBuilder.toString().replaceAll("# #", "##"));
        editText.setStartPosition(editText.getText().length());
        editText.setEndPosition(editText.getText().length());
    }

    /**
     * Add markdown bold markup.
     * If there was select something, add markup beside the selected text.
     * Otherwise, just add the markup and set the cursor position at the middle of markup.
     */
    public void bold() {
        int start = editText.getStartPosition();
        int end = editText.getEndPosition();
        StringBuilder stringBuilder = new StringBuilder();
        if (start == end) {
            stringBuilder.append(editText.getText());
            stringBuilder.insert(start, "****");
        } else {
            stringBuilder.append(editText.getText());
            stringBuilder.insert(start, "**");
            stringBuilder.insert(end + INT_2, "****");
        }
        editText.setText(stringBuilder.toString());
        editText.setStartPosition(editText.getText().length());
        editText.setEndPosition(editText.getText().length());
    }

    /**
     * Add markdown italic markup.
     * If there was select something, add markup beside the selected text.
     * Otherwise, just add the markup and set cursor position at the middle of markup.
     */
    public void italic() {
        // Add markdown italic markup
        int start = editText.getStartPosition();
        int end = editText.getEndPosition();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(editText.getText());
        if (start == end) {
            stringBuilder.insert(start, "**");
        } else {
            stringBuilder.insert(start, "*");
            stringBuilder.insert(end + 1, "*");
        }
        editText.setText(stringBuilder.toString());
        editText.setStartPosition(editText.getText().length());
        editText.setEndPosition(editText.getText().length());
    }

    /**
     * Add markdown code markup.
     * If there was select something, add markup beside the selected text.
     * Otherwise, open a dialog to input programming language name,
     * and insert block code markup after input.
     *
     */
    public void insertCode() {
        int start = editText.getStartPosition();
        int end = editText.getEndPosition();
        StringBuilder stringBuilder = new StringBuilder();
        if (start == end) { // Insert block code markup if there was nothing selected.
            ComponentContainer customToastLayout = (ComponentContainer) LayoutScatter
                    .getInstance(context).parse(ResourceTable.Layout_dialog_insert_layout, null, false);
            ComponentContainer.LayoutConfig layoutConfig = new ComponentContainer.LayoutConfig(
                    ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
            customToastLayout.setLayoutConfig(layoutConfig);
            Text title = (Text) customToastLayout.findComponentById(ResourceTable.Id_tv_title);
            TextField textField = (TextField) customToastLayout.findComponentById(ResourceTable.Id_tv_language);
            cutLanguage(textField, ResourceTable.String_dialog_et_hint_language_name,
                    ResourceTable.String_en_dialog_et_hint_language_name,
                    ResourceTable.String_tw_dialog_et_hint_language_name);
            cutLanguage(title, ResourceTable.String_editor_dialog_title_insert_block_code,
                    ResourceTable.String_en_editor_dialog_title_insert_block_code,
                    ResourceTable.String_tw_editor_dialog_title_insert_block_code
            );
            CommonDialog toastDialog = new CommonDialog(context);
            toastDialog.setContentCustomComponent(customToastLayout);
            toastDialog.setAutoClosable(true);
            toastDialog.setSize(ScreenUtils.getDisplayWidth(context) / INT_7 * INT_6,
                    DirectionalLayout.LayoutConfig.MATCH_CONTENT);
            toastDialog.setAlignment(LayoutAlignment.CENTER);
            toastDialog.show();
            Text insertText = (Text) customToastLayout.findComponentById(ResourceTable.Id_tv_insert);
            cutLanguage(insertText, ResourceTable.String_insert, ResourceTable.String_en_insert, ResourceTable.String_tw_dialog_btn_insert);
            insertText.setClickedListener(new Component.ClickedListener() {
                @Override
                public void onClick(Component component) {
                    BaseTextField textField = (BaseTextField) customToastLayout
                            .findComponentById(ResourceTable.Id_tv_language);
                    String langName = textField.getText();
                    int end = editText.getEndPosition();
                    stringBuilder.append(editText.getText());
                    stringBuilder.insert(end, "\n```" + langName + "\n\n```\n");
                    editText.setText(stringBuilder.toString());
                    toastDialog.hide();
                    toastDialog.remove();
                    editText.setStartPosition(editText.getText().length());
                    editText.setEndPosition(editText.getText().length());
                    HiLog.info(hiLogLabel, "" + editText.getStartPosition());
                }
            });
            Text cancel = (Text) customToastLayout.findComponentById(ResourceTable.Id_tv_cancel);
            cutLanguage(cancel, ResourceTable.String_cancel, ResourceTable.String_en_cancel, ResourceTable.String_tw_cancel);
            cancel.setClickedListener(new Component.ClickedListener() {
                @Override
                public void onClick(Component component) {
                    toastDialog.hide();
                    toastDialog.remove();
                }
            });
        } else { // Otherwise, insert inline code markup
            stringBuilder.append(editText.getText());
            stringBuilder.insert(start, "`");
            stringBuilder.insert(end + 1, "`");
            editText.setText(stringBuilder.toString());
        }
    }

    /**
     * Add markdown block quote markup.
     */
    public void quote() {
        StringBuilder stringBuilder = new StringBuilder();
        int start = editText.getStartPosition();
        int end = editText.getEndPosition();
        stringBuilder.append(editText.getText());
        if (start == end) {
            stringBuilder.insert(start, "> ");
        } else {
            stringBuilder.insert(start, "\n\n> ");
        }
        editText.setText(stringBuilder.toString());
        editText.setStartPosition(editText.getText().length());
        editText.setEndPosition(editText.getText().length());
    }

    /**
     * Add markdown ordered list markup.
     */
    public void orderedList() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(editText.getText());
        int start = editText.getStartPosition();
        stringBuilder.insert(start, "\n1. ");
        editText.setText(stringBuilder.toString());
        editText.setStartPosition(editText.getText().length());
        editText.setEndPosition(editText.getText().length());
    }

    /**
     * Add markdown unordered list markup.
     */
    public void unorderedList() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(editText.getText());
        int start = editText.getStartPosition();
        stringBuilder.insert(start, "\n* ");
        editText.setText(stringBuilder.toString());
        editText.setStartPosition(editText.getText().length());
        editText.setEndPosition(editText.getText().length());
    }

    /**
     * Insert markdown link markup.
     */
    public void insertLink() {
        ComponentContainer customToastLayout = (ComponentContainer) LayoutScatter
                .getInstance(context).parse(ResourceTable.Layout_dialog_insert_link, null, false);
        BaseTextField linkDisplayTextEt = (BaseTextField) customToastLayout
                .findComponentById(ResourceTable.Id_link_display_text);
        BaseTextField linkContentEt = (BaseTextField) customToastLayout
                .findComponentById(ResourceTable.Id_link_content);
        Text title = (Text) customToastLayout.findComponentById(ResourceTable.Id_insert_link);
        cutLanguage(linkDisplayTextEt, ResourceTable.String_dialog_show_text, ResourceTable.String_en_dialog_show_text, ResourceTable.String_tw_dialog_et_hint_link_display_text);
        cutLanguage(title, ResourceTable.String_dialog_title_insert_link,
                ResourceTable.String_en_dialog_title_insert_link,
                ResourceTable.String_tw_dialog_title_insert_link);
        cutLanguage(linkContentEt, ResourceTable.String_dialog_et_hint_link_content,
                ResourceTable.String_en_dialog_et_hint_link_content,
                ResourceTable.String_tw_dialog_et_hint_link_content);
        ComponentContainer.LayoutConfig layoutConfig = new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
        customToastLayout.setLayoutConfig(layoutConfig);

        CommonDialog toastDialog = new CommonDialog(context);
        toastDialog.setContentCustomComponent(customToastLayout);
        toastDialog.setAutoClosable(true);
        toastDialog.setSize(ScreenUtils.getDisplayWidth(context) / INT_7 * INT_6,
                DirectionalLayout.LayoutConfig.MATCH_CONTENT);
        toastDialog.setAlignment(LayoutAlignment.CENTER);
        toastDialog.show();

        int start = editText.getStartPosition();
        int end = editText.getEndPosition();
        if (start < end) {
            String selectedContent = editText.getText().subSequence(start, end).toString();
            linkDisplayTextEt.setText(selectedContent);
            linkContentEt.requestFocus();
        }
        Text cancel = (Text) customToastLayout.findComponentById(ResourceTable.Id_tv_cancel);
        cutLanguage(cancel, ResourceTable.String_cancel, ResourceTable.String_en_cancel, ResourceTable.String_tw_cancel);
        cancel.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                toastDialog.hide();
                toastDialog.remove();
            }
        });
        Text insertText = (Text) customToastLayout.findComponentById(ResourceTable.Id_tv_insert);
        StringBuilder stringBuilder = new StringBuilder();
        cutLanguage(insertText, ResourceTable.String_insert, ResourceTable.String_en_insert, ResourceTable.String_tw_dialog_btn_insert);
        insertText.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                stringBuilder.append(editText.getText());
                String linkDisplayText = linkDisplayTextEt.getText();
                String linkContent = linkContentEt.getText();
                if (linkDisplayText.equals("")) {
                    linkDisplayText = "Link";
                }
                String content = "[" + linkDisplayText + "]" + "(" + linkContent + ")";
                if (start == end) {
                    stringBuilder.insert(start, content);
                } else {
                    stringBuilder.replace(start, end, content);
                }
                editText.setText(stringBuilder.toString());
                toastDialog.hide();
                toastDialog.remove();
                editText.setStartPosition(editText.getText().length());
                editText.setEndPosition(editText.getText().length());
            }
        });
    }

    /**
     * Insert markdown image markup.
     *
     * @param displayText display text of image.
     * @param imageUri the uri of image.
     */
    public void insertImage(String displayText, String imageUri) {
        StringBuilder stringBuilder = new StringBuilder();
        int start = editText.getStartPosition();
        stringBuilder.append(editText.getText());
        stringBuilder.insert(start, "\n\n![" + displayText + "](" + imageUri + ")\n\n");
        editText.setText(stringBuilder.toString());
        editText.setStartPosition(editText.getText().length());
        editText.setEndPosition(editText.getText().length());
    }

    /**
     * Undo
     */
    public void undo() {
        List<String> undoList = editText.getUndoList();
        if (undoList.size() > 0) {
            editText.addRedoList(editText.getText());
            if (undoList.size() > 1) {
                if (undoList.get(undoList.size() - INT_2).equals(editText.getText())) {
                    editText.setText(undoList.get(undoList.size() - 1));
                } else {
                    editText.setText(undoList.get(undoList.size() - INT_2));
                }
            } else {
                editText.setText("");
            }
            editText.removeUndoList(undoList.size() - 1);
        }
    }

    /**
     * Redo
     */
    public void redo() {
        List<String> redoList = editText.getRedoList();
        HiLog.info(hiLogLabel, "" + redoList.size());
        if (redoList.size() > 0) {
            editText.setText(redoList.get(redoList.size() - 1));
            editText.removeRedoList(redoList.size() - 1);
        }
    }

    /**
     * Clear text in component.
     */
    public void clearAll() {
        if (editText.getText().equals("")) {
            new ToastDialog(editText.getContext()).setText("ssss").show();
        } else {
            ComponentContainer customToastLayout = (ComponentContainer) LayoutScatter
                    .getInstance(context).parse(ResourceTable.Layout_clear_all_layout, null, false);

            CommonDialog toastDialog = new CommonDialog(context);
            toastDialog.setContentCustomComponent(customToastLayout);
            toastDialog.setAutoClosable(true);
            toastDialog.setSize(ScreenUtils.getDisplayWidth(context) / INT_7 * INT_6,
                    DirectionalLayout.LayoutConfig.MATCH_CONTENT);
            toastDialog.setAlignment(LayoutAlignment.CENTER);
            toastDialog.show();
            Text cancel = (Text) customToastLayout.findComponentById(ResourceTable.Id_clear_all_cancel);
            cancel.setClickedListener(new Component.ClickedListener() {
                @Override
                public void onClick(Component component) {
                    toastDialog.remove();
                }
            });
            Text right = (Text) customToastLayout.findComponentById(ResourceTable.Id_clear_all_right);
            right.setClickedListener(new Component.ClickedListener() {
                @Override
                public void onClick(Component component) {
                    editText.setText("");
                    toastDialog.remove();
                }
            });
        }
    }

    /**
     * Opening docs fragment
     */
    public void checkDocs() {
    }

    /**
     * statistics di
     */
    public void statistics() {
        ComponentContainer customToastLayout = (ComponentContainer) LayoutScatter
                .getInstance(context).parse(ResourceTable.Layout_statistics_layout, null, false);

        CommonDialog toastDialog = new CommonDialog(context);
        toastDialog.setContentCustomComponent(customToastLayout);
        toastDialog.setAutoClosable(true);
        toastDialog.setSize(ScreenUtils.getDisplayWidth(context) / INT_7 * INT_6,
                DirectionalLayout.LayoutConfig.MATCH_CONTENT);
        toastDialog.setAlignment(LayoutAlignment.CENTER);
        toastDialog.show();
        Text stringnum = (Text) customToastLayout.findComponentById(ResourceTable.Id_statistics_string_num);
        stringnum.setText(editText.getText().length() + ResourceTable.String_only_strings);
        Text right = (Text) customToastLayout.findComponentById(ResourceTable.Id_statistics_right);
        right.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                toastDialog.remove();
            }
        });
    }

    private void cutLanguage(Text text, int chResource, int enResource, int twResource) {
        int anInt = PreferenceUtil.getInstance().getInt("int", 0);
        StringCache.getInstance().setLanguageType(anInt);
        if (StringCache.getInstance().getLanguageType() == StringCache.Default || StringCache.getInstance().getLanguageType() == StringCache.Chinese) {
            text.setText(context.getString(chResource));
        } else if (StringCache.getInstance().getLanguageType() == StringCache.English) {
            text.setText(context.getString(enResource));
        } else if (StringCache.getInstance().getLanguageType() == StringCache.Chinesefont) {
            text.setText(context.getString(twResource));
        }
    }

    private void cutLanguage(TextField text, int chResource, int enResource, int twResource) {
        int anInt = PreferenceUtil.getInstance().getInt("int", 0);
        StringCache.getInstance().setLanguageType(anInt);
        if (StringCache.getInstance().getLanguageType() == StringCache.Default || StringCache.getInstance().getLanguageType() == StringCache.Chinese) {
            text.setHint(context.getString(chResource));
        } else if (StringCache.getInstance().getLanguageType() == StringCache.English) {
            text.setHint(context.getString(enResource));
        } else if (StringCache.getInstance().getLanguageType() == StringCache.Chinesefont) {
            text.setText(context.getString(twResource));
        }
    }
}
